package ui.activity.login;

import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.IntentSender;
import android.content.SharedPreferences;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.Signature;
import android.os.AsyncTask;
import android.os.Build;
import android.os.Bundle;
import android.util.Base64;
import android.util.Log;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.View;
import android.view.inputmethod.EditorInfo;
import android.widget.EditText;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;

import com.facebook.AccessToken;
import com.facebook.AccessTokenTracker;
import com.facebook.CallbackManager;
import com.facebook.FacebookCallback;
import com.facebook.FacebookException;
import com.facebook.FacebookSdk;
import com.facebook.GraphRequest;
import com.facebook.GraphResponse;
import com.facebook.Profile;
import com.facebook.ProfileTracker;
import com.facebook.login.LoginManager;
import com.facebook.login.LoginResult;
import com.google.android.gms.common.GooglePlayServicesUtil;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.api.GoogleApiClient.ConnectionCallbacks;
import com.google.android.gms.common.api.GoogleApiClient.OnConnectionFailedListener;
import com.google.android.gms.common.api.ResultCallback;
import com.google.android.gms.common.api.Status;
import com.google.android.gms.plus.Plus;
import com.google.android.gms.plus.model.people.Person;
import com.trek2000.android.enterprise.R;

import org.json.JSONObject;

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;

import controller.login.GetCsAccountBySocialMediaAsync;
import controller.login.LogInAsync;
import controller.login.RegisterGCMClientAsync;
import define.Key;
import singleton.login.User;
import utils.Utils;

/**
 * Created by Dong Le on 5/22/2015.
 */
public class Login extends Activity implements View.OnClickListener,
        View.OnFocusChangeListener, TextView.OnEditorActionListener, View.OnTouchListener,
        ConnectionCallbacks, OnConnectionFailedListener{

    //string session
    public static Boolean IS_LOGIN_BY_FACEBOOK = false;
    public static Boolean IS_LOGIN_BY_GOOGLE_PLUS = false;

    //view session
    private EditText mEtEmail;
    private EditText mEtPassword;
    private ImageButton mIbtnEmailLogin;
    private ImageButton mIbtnFaceBookLogin;
    private ImageButton mIbtnGooglePlus;
    private ImageView mIvEmail;
    private ImageView mIvPassword;
    private LinearLayout mLlLoginActivity;
    // others session
    private Context mcontext;
    //save data when destroy app
    public static SharedPreferences mSp;
    public static SharedPreferences.Editor mSpEditor;
    //initial single ton
    public static User user = User.getInstance();
    //facebook login
    private  CallbackManager mCallbackManager;
    private AccessTokenTracker mAccessTokenTracker;
    private ProfileTracker mProfileTracker;
    //google plus
    /* Request code used to invoke sign in user interactions. */
    public static final int RC_SIGN_IN = 0;
    /* Client used to interact with Google APIs. */
    private GoogleApiClient mGoogleApiClient;
    /* A flag indicating that a PendingIntent is in progress and prevents
  * us from starting further intents.
  */
    private boolean mIntentInProgress;
    /* Track whether the sign-in button has been clicked so that we know to resolve
 * all issues preventing sign-in without waiting.
 */
    public static boolean mSignInClicked;
    /* Store the connection result from onConnectionFailed callbacks so that we can
 * resolve them when the user clicks sign-in.
 */
    private ConnectionResult mConnectionResult;
//    public static Boolean HAS_ALREADY_GET_GOOGLE_INFO = false;

    private FacebookCallback<LoginResult> mFacebookCallback = new FacebookCallback<LoginResult>() {
        @Override
        public void onSuccess(LoginResult loginResult) {
            GraphRequest.newMeRequest(loginResult.getAccessToken(), new GraphRequest.GraphJSONObjectCallback() {
                @Override
                public void onCompleted(JSONObject user, GraphResponse response) {
                    if (user != null) {
                        Log.i("","JSONObject user: " + user);
                        Log.i("","user.optString(Key.EMAIL) " + user.optString(Key.EMAIL));
                        Log.i("","user.optString(Key.FIRST_NAME): " + user.optString(Key.FIRST_NAME));
                        Log.i("","user.optString(Key.LAST_NAME) " + user.optString(Key.LAST_NAME));

                        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB)
                            new GetCsAccountBySocialMediaAsync(mcontext).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR,
                                    user.optString(Key.EMAIL), mcontext.getString(R.string.fb),
                                    mcontext.getString(R.string.true_), user.optString(Key.FIRST_NAME),
                                    user.optString(Key.LAST_NAME),
                                    Login.user.getDeviceToken(), Key.ANDROID);
                        else
                            new GetCsAccountBySocialMediaAsync(mcontext).execute(
                                    user.optString(Key.EMAIL), mcontext.getString(R.string.fb),
                                    mcontext.getString(R.string.true_), user.optString(Key.FIRST_NAME),
                                    user.optString(Key.LAST_NAME),
                                    Login.user.getDeviceToken(), Key.ANDROID);
                    }
                }
            }).executeAsync();
        }

        @Override
        public void onCancel() {

        }

        @Override
        public void onError(FacebookException e) {

        }
    };

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        mCallbackManager.onActivityResult(requestCode, resultCode, data);

        if (requestCode == RC_SIGN_IN) {
            Log.i("","onActivityResult RC_SIGN_IN ");
            if (resultCode != RESULT_OK) {
                mSignInClicked = false;
            }

            mIntentInProgress = false;

            if (!mGoogleApiClient.isConnecting()) {
                mGoogleApiClient.connect();
            }
        }
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.ibtn_email_login_in_login_activity:
                /**
                 * Check edit text is not empty
                 */
                if (!Utils.checkFillBlank(mEtEmail)
                        && !Utils.checkFillBlank(mEtPassword)) {
                    /**
                     * Check email is suitable or not
                     */
                    if (Utils.isEmailValid(mEtEmail)) {
                        if (Utils.checkValidatePassword(mEtPassword, 6)) {
                            /**
                             * Call new thread to log in specify account
                             */
                            if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB)
                                new LogInAsync(this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR,
                                        mEtEmail.getText().toString(), mEtPassword.getText().toString(),
                                        user.getDeviceToken(), Key.ANDROID);
                            else
                                new LogInAsync(this).execute(
                                        mEtEmail.getText().toString(), mEtPassword.getText().toString(),
                                        user.getDeviceToken(), Key.ANDROID);
                        } else {
                            Toast.makeText(getApplicationContext(),
                                    getString(R.string.toast_your_password_is_case_sensitive),
                                    Toast.LENGTH_SHORT).show();
                        }
                    } else {
                        Toast.makeText(getApplicationContext(), getString(R.string.toast_email_is_invalid),
                                Toast.LENGTH_SHORT).show();
                    }
                } else {
                    Toast.makeText(getApplicationContext(), getString(R.string.toast_fill_in_the_blank),
                            Toast.LENGTH_SHORT).show();
                }
                break;
            case R.id.ibtn_facebook_login_in_login_activity:
                IS_LOGIN_BY_FACEBOOK = true;
                LoginManager.getInstance().logInWithReadPermissions(this, Arrays.asList("public_profile", "email", "user_friends"));
                break;
            case R.id.ibtn_google_plus_login_in_login_activity:
                IS_LOGIN_BY_GOOGLE_PLUS = true;
                signInWithGplus();
                break;
        }
    }

    @Override
    public void onConnected(Bundle bundle) {
        Log.i("Connected G+ ", "Connected G+ ");

        mSignInClicked = false;
        //get profile info google plus
//        if (!HAS_ALREADY_GET_GOOGLE_INFO)
        getProfileInformationGooglePlusAccount();
    }

    @Override
    public void onConnectionSuspended(int i) {
        mGoogleApiClient.connect();
    }

    @Override
    public void onConnectionFailed(ConnectionResult connectionResult) {
        if (!connectionResult.hasResolution()) {
            GooglePlayServicesUtil.getErrorDialog(connectionResult.getErrorCode(), this, 0).show();
            return;
        }

        if (!mIntentInProgress) {
            // Store the ConnectionResult so that we can use it later when the user clicks
            // 'sign-in'.
            mConnectionResult = connectionResult;

            if (mSignInClicked) {
                // The user has already clicked 'sign-in' so we attempt to resolve all
                // errors until the user is signed in, or they cancel.
                resolveSignInError();
            }
        }
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_login);
        mcontext = this;
        initialView();
        initialData();

        initialSharedPreferences();

        registerGCM(this);

        getKeyHashes();
        initialSdkFacebook();
        trackAccessTokenAndProfileTracker();

        initialGooglePlus();

        checkAutoLogin();
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        mAccessTokenTracker.stopTracking();
        mProfileTracker.stopTracking();
        LoginManager.getInstance().logOut();
    }

    @Override
    public boolean onEditorAction(TextView textView, int i, KeyEvent keyEvent) {
        switch (i) {
            case EditorInfo.IME_ACTION_DONE:
                /**
                 * Check edit text is not empty
                 */
                if (!Utils.checkFillBlank(mEtEmail)
                        && !Utils.checkFillBlank(mEtPassword)) {
                    /**
                     * Check email is suitable or not
                     */
                    if (Utils.isEmailValid(mEtEmail)) {
                        if (Utils.checkValidatePassword(mEtPassword, 6)) {
                            /**
                             * Call new thread to log in specify account
                             */
                            if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB)
                                new LogInAsync(this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR,
                                        mEtEmail.getText().toString(), mEtPassword.getText().toString(),
                                        user.getDeviceToken(), Key.ANDROID);
                            else
                                new LogInAsync(this).execute(
                                        mEtEmail.getText().toString(), mEtPassword.getText().toString(),
                                        user.getDeviceToken(), Key.ANDROID);
                        } else {
                            Toast.makeText(getApplicationContext(),
                                    getString(R.string.toast_your_password_is_case_sensitive),
                                    Toast.LENGTH_SHORT).show();
                        }
                    } else {
                        Toast.makeText(getApplicationContext(), getString(R.string.toast_email_is_invalid),
                                Toast.LENGTH_SHORT).show();
                    }
                } else {
                    Toast.makeText(getApplicationContext(), getString(R.string.toast_fill_in_the_blank),
                            Toast.LENGTH_SHORT).show();
                }
                break;
        }
        return false;
    }

    @Override
    public void onFocusChange(View v, boolean hasFocus) {
        switch (v.getId()) {
            case R.id.et_email_in_login_activity:
                if (hasFocus) {
                    mIvEmail.setImageResource(R.drawable.iv_email_login_focus);
                } else if (!"".equals(mEtEmail.getText().toString())) {
                    mIvEmail.setImageResource(R.drawable.iv_email_login_focus);
                } else if ("".equals(mEtEmail.getText().toString())) {
                    mIvEmail.setImageResource(R.drawable.iv_email_login_normal);
                }
                break;
            case R.id.et_password_in_login_activity:
                if (hasFocus) {
                    mIvPassword.setImageResource(R.drawable.iv_password_login_focus);
                } else if (!"".equals(mEtPassword.getText().toString())) {
                    mIvPassword.setImageResource(R.drawable.iv_password_login_focus);
                } else if ("".equals(mEtPassword.getText().toString())) {
                    mIvPassword.setImageResource(R.drawable.iv_password_login_normal);
                }
                break;
        }
    }

    @Override
    public void onStart() {
        super.onStart();
        mGoogleApiClient.connect();
    }


    @Override
    protected void onStop() {
        super.onStop();
        mAccessTokenTracker.stopTracking();
        mProfileTracker.stopTracking();
        LoginManager.getInstance().logOut();

        if (mGoogleApiClient.isConnected()) {
            mGoogleApiClient.disconnect();
        }
    }

    @Override
    public boolean onTouch(View v, MotionEvent motionEvent) {
        switch (v.getId()) {
            case R.id.ll_login_activity:
                Utils.hideSoftKeyboard(this, mEtEmail);
                Utils.hideSoftKeyboard(this, mEtPassword);
                break;
        }
        return false;
    }

    private void initialData() {
        mIbtnEmailLogin.setOnClickListener(this);
        mIbtnFaceBookLogin.setOnClickListener(this);
        mIbtnGooglePlus.setOnClickListener(this);
        mEtEmail.setOnFocusChangeListener(this);
        mEtPassword.setOnFocusChangeListener(this);
        mEtPassword.setOnEditorActionListener(this);
        mLlLoginActivity.setOnTouchListener(this);
    }

    private void initialView() {
        mEtEmail  = (EditText) findViewById(R.id.et_email_in_login_activity);
        mEtPassword  = (EditText) findViewById(R.id.et_password_in_login_activity);
        mIbtnEmailLogin = (ImageButton) findViewById(R.id.ibtn_email_login_in_login_activity);
        mIbtnFaceBookLogin = (ImageButton) findViewById(R.id.ibtn_facebook_login_in_login_activity);
        mIbtnGooglePlus = (ImageButton) findViewById(R.id.ibtn_google_plus_login_in_login_activity);
        mIvEmail = (ImageView) findViewById(R.id.iv_email_in_login_activity);
        mIvPassword = (ImageView) findViewById(R.id.iv_password_in_login_activity);
        mLlLoginActivity = (LinearLayout) findViewById(R.id.ll_login_activity);
    }

    private void initialSharedPreferences () {
        mSp = getSharedPreferences(Key.ENTERPRISE_PREFERENCES, 0);
        mSpEditor = mSp.edit();
    }

    private void registerGCM(Context mContext) {
        Log.i("","mSp.getString(Key.DEVICE_TOKEN, ) " + mSp.getString(Key.DEVICE_TOKEN, ""));
        if ("".equals(mSp.getString(Key.DEVICE_TOKEN, ""))) {
            new RegisterGCMClientAsync(mContext).execute();
        } else {
            user.setDeviceToken(mSp.getString(Key.DEVICE_TOKEN, ""));
        }
    }

    private void getKeyHashes () {
        // code for get key hash facebook
        PackageInfo info;
        try {
            info = getPackageManager().getPackageInfo("com.trek2000.android.enterprise", PackageManager.GET_SIGNATURES);
            for (Signature signature : info.signatures) {
                MessageDigest md;
                md = MessageDigest.getInstance("SHA");
                md.update(signature.toByteArray());
                String something = new String(Base64.encode(md.digest(), 0));
                //String something = new String(Base64.encodeBytes(md.digest()));
                Log.e("hash key", something);
            }
        } catch (PackageManager.NameNotFoundException e1) {
            Log.e("name not found", e1.toString());
        } catch (NoSuchAlgorithmException e) {
            Log.e("no such an algorithm", e.toString());
        } catch (Exception e) {
            Log.e("exception", e.toString());
        }
    }

    private void initialSdkFacebook () {
        FacebookSdk.sdkInitialize(getApplicationContext());
        mCallbackManager = CallbackManager.Factory.create();
        LoginManager.getInstance().registerCallback(mCallbackManager, mFacebookCallback);
    }

    private void trackAccessTokenAndProfileTracker () {
        mAccessTokenTracker = new AccessTokenTracker() {
            @Override
            protected void onCurrentAccessTokenChanged(AccessToken accessToken, AccessToken accessToken1) {

            }
        };
        mProfileTracker  = new ProfileTracker() {
            @Override
            protected void onCurrentProfileChanged(Profile profile, Profile profile1) {

            }
        };
        mAccessTokenTracker.startTracking();
        mProfileTracker.startTracking();
    }

    private void initialGooglePlus () {
        mGoogleApiClient = new GoogleApiClient.Builder(this)
                .addConnectionCallbacks(this)
                .addOnConnectionFailedListener(this)
                .addApi(Plus.API)
                .addScope(Plus.SCOPE_PLUS_LOGIN)
                .build();
    }

    /* A helper method to resolve the current ConnectionResult error. */
    private void resolveSignInError() {
        Log.i ("","mConnectionResult.hasResolution() " + mConnectionResult.hasResolution());
        if (mConnectionResult.hasResolution()) {
            try {
                mIntentInProgress = true;
                mConnectionResult.startResolutionForResult(this, RC_SIGN_IN);
            } catch (IntentSender.SendIntentException e) {
                // The intent was canceled before it was sent.  Return to the default
                // state and attempt to connect to get an updated ConnectionResult.
                mIntentInProgress = false;
                mGoogleApiClient.connect();
            }
        }
    }

    /**
     * Sign-in into google
     * */
    private void signInWithGplus() {
        if (!mGoogleApiClient.isConnecting()) {
            mSignInClicked = true;
            resolveSignInError();
        }
    }

    /**
     * Sign-out from google
     * */
    private void signOutFromGplus() {
        Log.i("","sign out google plus");
        if (mGoogleApiClient.isConnected()) {
            Plus.AccountApi.clearDefaultAccount(mGoogleApiClient);
            mGoogleApiClient.disconnect();
//            mGoogleApiClient.connect();
        }
    }

    /**
     * Revoking access from google
     * */
    private void revokeGplusAccess() {
        if (mGoogleApiClient.isConnected()) {
            Plus.AccountApi.clearDefaultAccount(mGoogleApiClient);
            Plus.AccountApi.revokeAccessAndDisconnect(mGoogleApiClient)
                    .setResultCallback(new ResultCallback<Status>() {
                        @Override
                        public void onResult(Status arg0) {
                            Log.e("", "User access revoked!");
                            mGoogleApiClient.connect();
                        }

                    });
        }
    }

    //get profile info google plus
    private void getProfileInformationGooglePlusAccount() {
        try {
            if (Plus.PeopleApi.getCurrentPerson(mGoogleApiClient) != null) {
                Person currentPerson = Plus.PeopleApi
                        .getCurrentPerson(mGoogleApiClient);
                String personName = currentPerson.getDisplayName();
                String personPhotoUrl = currentPerson.getImage().getUrl();
                String personGooglePlusProfile = currentPerson.getUrl();
                String email = Plus.AccountApi.getAccountName(mGoogleApiClient);
                Person.Name name = currentPerson.getName();
                String firstname = name.getGivenName();
                String lastname = name.getFamilyName();

                Log.i("", "Name: " + personName + ", plusProfile: "
                        + personGooglePlusProfile + ", email: " + email
                        + ", Image: " + personPhotoUrl);
                Log.i("", "firstname" + firstname);
                Log.i("", "lastname" + lastname);

                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB)
                    new GetCsAccountBySocialMediaAsync(this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR,
                            email,
                            mcontext.getString(R.string.gplus),
                            mcontext.getString(R.string.true_),
                            firstname,lastname,
                            user.getDeviceToken(), Key.ANDROID
                    );
                else
                    new GetCsAccountBySocialMediaAsync(this).execute(
                            email,
                            mcontext.getString(R.string.gplus),
                            mcontext.getString(R.string.true_),
                            firstname, lastname,
                            user.getDeviceToken(), Key.ANDROID
                    );
                // by default the profile url gives 50x50 px image only
                // we can replace the value with whatever dimension we want by
                // replacing sz=X
//                HAS_ALREADY_GET_GOOGLE_INFO = true;
                signOutFromGplus();
            } else {
                Toast.makeText(this,
                        "Person information is null", Toast.LENGTH_LONG).show();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private void checkAutoLogin () {
        Log.i("","Login.mSp.getString(Key.ACCESS_TOKEN, )" + Login.mSp.getString(Key.ACCESS_TOKEN, ""));
        Log.i("","Login.mSp.getString(Key.USER_EMAIL, )" + Login.mSp.getString(Key.USER_EMAIL, ""));
        Log.i("","Login.mSp.getString(Key.PASSWORD, )" + Login.mSp.getString(Key.PASSWORD, ""));

        if (!"".equals(Login.mSp.getString(Key.ACCESS_TOKEN, ""))) {
            /**
             * Call new thread to log in specify account
             */
            if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB)
                new LogInAsync(this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR,
                        mSp.getString(Key.USER_EMAIL, ""), mSp.getString(Key.ACCESS_TOKEN, ""),
                        user.getDeviceToken(), Key.ANDROID);
            else
                new LogInAsync(this).execute(
                        mSp.getString(Key.USER_EMAIL, ""), mSp.getString(Key.ACCESS_TOKEN, ""),
                        user.getDeviceToken(), Key.ANDROID);
        }
    }
}
